package org.zoomdev.zoom.dao.meta;

import org.zoomdev.zoom.dao.DaoException;
import org.zoomdev.zoom.dao.utils.SqlUtils;

import java.util.Objects;

import static org.zoomdev.zoom.dao.utils.SqlUtils.escapeSql;

/**
 * 元数据模型类
 */
public final class TableMeta {


    private String comment;
    private String name;
    private String engine;
    /**
     * 所有列
     */
    private ColumnMeta[] columns;
    /**
     * 所有主键
     */
    private String[] primaryKeys;
    /**
     * 所有索引
     */
    private IndexMeta[] indexes;

    public TableMeta() {

    }

    public String toSql(boolean ifNotExists, boolean pretty) {
        if (SqlUtils.isInvalidName(name)) {
            throw new DaoException("表名不合法" + name);
        }

        StringBuilder sql = new StringBuilder(512);
        sql.setLength(0);
        // Create table
        sql.append("CREATE TABLE ");
        if (ifNotExists) {
            sql.append("IF NOT EXISTS ");
        }

        sql.append(name);
        if (pretty) {
            sql.append(" (\n");
        } else {
            sql.append("(");
        }

        // Columns
        for (ColumnMeta col : columns) {
            if (SqlUtils.isInvalidName(col.getName())) {
                throw new DaoException("字段名不合法" + col.getName());
            }

            col.toSql(sql, primaryKeys, pretty);

            if (col != columns[columns.length - 1]) {
                sql.append(",");
            } else {
                if ((indexes != null && indexes.length > 0)
                        || (primaryKeys != null && primaryKeys.length > 1)) sql.append(",");
            }

            if (pretty) {
                sql.append("\n");
            }
        }

        // Primary key constraint
        if (primaryKeys != null && primaryKeys.length > 1) {
            sql.append("  PRIMARY KEY (");
            for (int i = 0; i < primaryKeys.length; i++) {
                if (i > 0) sql.append(", ");
                sql.append(primaryKeys[i]);
            }
            sql.append(")");
            if (indexes != null && indexes.length > 0) sql.append(",");
            sql.append("\n");
        }

        if (indexes != null && indexes.length > 0) {
            // Index definitions
            for (int i = 0; i < indexes.length; i++) {
                IndexMeta idx = indexes[i];
                idx.toSql(sql, pretty);
                if (i < indexes.length - 1) sql.append(",");
                if (pretty) {
                    sql.append("\n");
                }

            }
        }


        sql.append(")");

        // Engine specification
        if (engine != null && !engine.isEmpty()) {
            sql.append(" ENGINE=").append(engine);
        }

        // Table comment
        if (comment != null && !comment.isEmpty()) {
            sql.append(" COMMENT='").append(escapeSql(comment)).append("'");
        }

        return sql.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof TableMeta)) return false;
        TableMeta tableMeta = (TableMeta) o;
        return Objects.equals(comment, tableMeta.comment)
                && Objects.equals(name, tableMeta.name)
                && Objects.equals(engine, tableMeta.engine)
                && Objects.deepEquals(columns, tableMeta.columns)
                && Objects.deepEquals(primaryKeys, tableMeta.primaryKeys)
                && Objects.deepEquals(indexes, tableMeta.indexes);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEngine() {
        return engine;
    }

    public void setEngine(String engine) {
        this.engine = engine;
    }


    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }


    public String[] getPrimaryKeys() {
        return primaryKeys;
    }

    public void setPrimaryKeys(String[] primaryKeys) {
        this.primaryKeys = primaryKeys;
    }

    public IndexMeta[] getIndexes() {
        return indexes;
    }

    public void setIndexes(IndexMeta[] indexes) {
        this.indexes = indexes;
    }

    public ColumnMeta[] getColumns() {
        return columns;
    }

    public void setColumns(ColumnMeta[] columns) {
        this.columns = columns;
    }


}

